import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  ManyToMany,
  ManyToOne,
  Index,
  CreateDateColumn,
  UpdateDateColumn,
  OneToOne,
  JoinColumn,
  DeleteDateColumn,
  OneToMany,
} from 'typeorm';
import {
  IsOptional,
  IsNotEmpty,
  IsString,
  MaxLength,
  IsNumber,
  IsBoolean,
} from 'class-validator';
import { Type } from 'class-transformer';
import { CrudValidationGroups } from '@nestjsx/crud';
import { User } from '@/modules/users/entities/user.entity';
import { PlayList } from '@/modules/resources/entities/play-list.entity';
import { Artist } from './artist.entity';
import { Album } from './album.entity';
import { ResourceFile } from './resource-file.entity';
import { Score } from './score.entity';
import { Post } from './post.entity';
import { Track } from './track.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

@Entity({ name: 'songs' })
export class Song {
  @IsOptional({ always: true })
  @PrimaryGeneratedColumn()
  id: number;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  @MaxLength(200, { always: true })
  @Index()
  @Column({ type: 'character varying', length: 200 })
  title: string;

  @IsOptional({ always: true })
  @IsNumber()
  @Column({ type: 'real', comment: '时长/秒' })
  duration: number;

  @Type(_type => ResourceFile)
  @OneToOne(_type => ResourceFile)
  @JoinColumn()
  audioFile: ResourceFile;

  @Type(_type => ResourceFile)
  @OneToOne(_type => ResourceFile)
  @JoinColumn()
  mv: ResourceFile;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @Column({ type: 'int', default: 0 })
  playedCount = 0;

  @IsOptional({ always: true })
  @IsString({ always: true })
  @Column({ type: 'text', nullable: true })
  lyric: string;

  @IsOptional({ always: true })
  @IsBoolean({ always: true })
  @Column({ type: 'boolean', default: true })
  visible = true;

  @Type(_type => Artist)
  @ManyToMany(
    _type => Artist,
    artist => artist.hasSongs,
  )
  belongsToArtists: Artist[];

  @Type(_type => Album)
  @ManyToOne(
    _type => Album,
    album => album.hasSongs,
  )
  belongsToAlbum: Album;

  @Type(_type => User)
  @ManyToMany(
    _type => User,
    user => user.favSongs,
  )
  favByUsers: User[];

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsNumber({}, { always: true })
  @Column({ type: 'int', default: 0 })
  favCount = 0;

  @Type(_type => PlayList)
  @ManyToMany(
    _type => PlayList,
    playlist => playlist.songs,
  )
  inPlayLists: PlayList[];

  @Type(_type => Score)
  @OneToMany(
    _type => Score,
    score => score.relatedSong,
  )
  scores: Score[];

  @Type(_type => Track)
  @OneToMany(
    _type => Track,
    track => track.relatedSong,
  )
  tracks: Track[];

  @Type(_type => Post)
  @ManyToMany(
    _type => Post,
    post => post.relatedSongs,
  )
  relatedPosts: Post[];

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date;
}
